<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue响应式原理</title>
</head>

<body>
    <!-- <script>
        var obj = {};
        Object.defineProperty(obj, 'a', {
            //给a属性定义值
            value: 6,
            //是否可写
            writable: false,
            //是否可以被枚举
            enumerable: true
        })
        Object.defineProperty(obj, 'b', {
            //给a属性定义值
            value: 10,
            //是否可以被枚举
            enumerable: false
        })
        console.log('obj.a', obj.a);//6
        obj.a = 10
        console.log('obj.a', obj.a);//6：因为设置了不可写
        for (const key in obj) {
            console.log('可枚举', key);//只会输出a，因为b设置了不可被枚举
        }
    </script> -->
    <!-- <script>
        //自定义defineReactive函数(data->要访问的对象，key->对象中的属性，val->要修改的属性值【闭包】)
        function defineReactive(data, key, val) {
            Object.defineProperty(data, key, {
                //可枚举
                enumerable: true,
                //可以被delete
                configurable: true,
                //getter：数据劫持
                get() {
                    console.log("正在访问" + key + "属性");
                    return val;
                },
                //setter
                set(newValue) {
                    console.log("正在改变" + key + "属性", newValue)
                    if (val !== newValue) {
                        val = newValue
                    }
                }
            })
        }
        var obj = {};
        defineReactive(obj, 'c', 10)
        console.log(obj.c);//10
    </script> -->
    <script>
        //自定义defineReactive函数(data->要访问的对象，key->对象中的属性，val->要修改的属性值【闭包】)
        function defineReactive(data, key, val) {
            console.log("defineReactive", key);
            //可以传两个参数
            if (arguments.length === 2) {
                val = data[key]
            }
            observe(val);
            Object.defineProperty(data, key, {
                //可枚举
                enumerable: true,
                //可以被delete
                configurable: true,
                //getter：数据劫持
                get() {
                    console.log("正在访问" + key + "属性");
                    return val;
                },
                //setter
                set(newValue) {
                    console.log("正在改变" + key + "属性", newValue)
                    if (val !== newValue) {
                        val = newValue
                        observe(newValue);
                    }
                }
            })
        }
        //设置属性能否被枚举
        function def(data, key, value, enumerable) {
            Object.defineProperty(obj, key, {
                value,
                enumerable,
                writable: true,
                configurable: true
            })
        }
        //能将object转化为每个层级的属性都是响应式的——可以被侦测的object
        class Observer {
            constructor(value) {
                //给实例添加__ob__属性，不可以被枚举，value为实例
                def(value, '__ob__', this, false);
                console.log("构造器", value)
                this.walk(value)
            }
            //遍历
            walk(value) {
                for (const key in value) {
                    defineReactive(value, key)
                }
            }
        }
        //创建observe函数,首先判断
        function observe(val) {
            if (typeof val !== 'object') return;
            var ob;
            if (typeof val.__ob__ !== 'undefined') {
                ob = val.__ob__;
            } else {
                ob = new Observer(val);
            }
            return ob

        }
        var obj = {
            a: {
                m: {
                    n: 5
                }
            },
            b: 10
        }
        observe(obj);
        console.log(obj.a.m.n);
    </script>
</body>

</html>